﻿using System;
using System.ServiceModel.Syndication;
using System.Windows;
using Jacobi.Seesmic.FeedReader.Model;
using Jacobi.Seesmic.FeedReader.Model.Extensions;
using Jacobi.Seesmic.FeedReader.Utilities;
using Seesmic.Sdp.Extensibility;

namespace Jacobi.Seesmic.FeedReader.FeedItemView
{
    /// <summary>
    /// This class represent the ViewModel to the item that is published on the timeline.
    /// </summary>
    /// <remarks>
    /// Implements the <see cref="ITimelineItem"/> interface.
    /// </remarks>
    public sealed class FeedItemViewModel : ITimelineItem
    {
        private static readonly Uri _defaultAvatarUri = new Uri("/Jacobi.Seesmic.FeedReader;component/Resources/Feed48.png", UriKind.Relative);

        /// <summary>
        /// Constructs a new instance based on the specified <paramref name="feedItem"/>.
        /// </summary>
        /// <param name="feedItem">Must not be null.</param>
        internal FeedItemViewModel(TimelineFeedItem feedItem)
        {
            feedItem.ThrowIfArgumentIsNull("feedItem");

            FeedItem = feedItem;
        }

        /// <summary>
        /// Gets or sets a tag object for this feed item.
        /// </summary>
        internal object Tag { get; set; }

        /// <summary>
        /// Gets the feed item provided in the constructor.
        /// </summary>
        internal TimelineFeedItem FeedItem { get; private set; }

        /// <summary>
        /// Gets the url to the content of the item.
        /// </summary>
        /// <remarks>
        /// First the 'alternate' or 'self' links on the item itself
        /// as well as the links on the feed (parent) are used to
        /// create an absolute url.
        /// </remarks>
        public Uri ContentUrl
        {
            get { return FeedItem.ContentUrl; }
        }

        private string _contentSourceName;

        /// <summary>
        /// Gets the name of the source of the content (Feed Title).
        /// </summary>
        public string ContentSourceName
        {
            get
            {
                if (_contentSourceName == null)
                {
                    _contentSourceName = FeedItem.SourceFeed.Title.Text;
                }

                return _contentSourceName;
            }
        }

        private Uri _contentSourceUrl;

        /// <summary>
        /// Gets the link to the source of the content (web site).
        /// </summary>
        public Uri ContentSourceUrl
        {
            get
            {
                if (_contentSourceUrl == null)
                {
                    var link = FeedItem.SourceFeed.Links.FindAlternateOrSelf();

                    if (link != null)
                    {
                        _contentSourceUrl = link.Uri;
                    }
                }

                return _contentSourceUrl;
            }
        }

        /// <summary>
        /// Gets the title of the item.
        /// </summary>
        public string Title
        {
            get { return FeedItem.Title.Text; }
        }

        private Uri _avatarUri;

        /// <summary>
        /// Gets the uri of the avatar image that is displayed beside the item.
        /// </summary>
        /// <remarks>
        /// The image url of the feed is used or a default when it is null.
        /// </remarks>
        public Uri AvatarUri
        {
            get
            {
                if (_avatarUri == null)
                {
                    var link = FeedItem.MediaLinks.FindAvatarLink();

                    if (link != null)
                    {
                        _avatarUri = link.Uri;
                    }
                    else if (FeedItem.SourceFeed.ImageUrl != null)
                    {
                        _avatarUri = FeedItem.SourceFeed.ImageUrl;
                    }
                    else
                    {
                        _avatarUri = _defaultAvatarUri;
                    }
                }

                return _avatarUri;
            }
        }

        /// <summary>
        /// Gets the publish date.
        /// </summary>
        public DateTimeOffset DateTime
        {
            get { return FeedItem.PublishDate; }
        }

        /// <summary>
        /// Gets the publish date.
        /// </summary>
        public DateTime Time
        {
            get { return FeedItem.PublishDate.UtcDateTime; }
        }

        /// <summary>
        /// Not used, always returns null.
        /// </summary>
        public GeoLocation GeoLocation
        {
            get { return null; }
        }

        /// <summary>
        /// Gets the unique Id of the item.
        /// </summary>
        /// <remarks>
        /// This Id must be unique or subsequent items with the same Id will NOT be displayed.
        /// </remarks>
        public string Id
        {
            get { return FeedItem.UniqueId; }
        }

        /// <summary>
        /// Not used, always returns null.
        /// </summary>
        public DataTemplate NotificationTemplate
        {
            get { return null; }
        }

        /// <summary>
        /// Gets the DataTemplate for displaying the item in the timeline.
        /// </summary>
        public DataTemplate Template
        {
            get { return FeedItemViews.DefaultView; }
        }

        private string _text;

        /// <summary>
        /// Gets the summary of the feed item.
        /// </summary>
        /// <remarks>
        /// When no summary is found in the feed item, the content is truncated to about 255 characters.
        /// </remarks>
        public string Text
        {
            get
            {
                if (_text == null)
                {
                    var textContent = FeedItem.Content as TextSyndicationContent;

                    if (FeedItem.Summary != null)
                    {
                        _text = TextHelper.DecodeText(FeedItem.Summary.Text);
                    }
                    else if (textContent != null)
                    {
                        _text = TextHelper.DecodeText(textContent.Text);
                    }

                    _text = TextHelper.TruncateText(_text, 255);
                }

                return _text;
            }
        }

        private SyndicationPerson _author;

        /// <summary>
        /// Gets the author object for this feed item. Can be null.
        /// </summary>
        /// <remarks>
        /// When multiple authors are present, the first is selected.
        /// </remarks>
        public SyndicationPerson Author
        {
            get
            {
                if (_author == null)
                {
                    if (FeedItem.Authors != null &&
                        FeedItem.Authors.Count > 0)
                    {
                        _author = FeedItem.Authors[0];
                    }
                    else if (FeedItem.SourceFeed.Authors != null &&
                            FeedItem.SourceFeed.Authors.Count > 0)
                    {
                        _author = FeedItem.SourceFeed.Authors[0];
                    }
                }

                return _author;
            }
        }

        /// <summary>
        /// Gets the name of the Author of the feed item.
        /// </summary>
        /// <remarks>
        /// When no authors on the feed item can be found, the feed (parent) is checked.
        /// When the feed also has no authors, the value of the creator extension tag is returned.
        /// </remarks>
        public string Username
        {
            get
            {
                if (Author != null)
                {
                    return Author.Name;
                }

                return FeedItem.Creator;
            }
        }

        private Uri _userUrl;

        /// <summary>
        /// Returns the link that displays the author's profile page (or similar).
        /// </summary>
        public Uri UserUrl
        {
            get
            {
                if (_userUrl == null)
                {
                    if (Author != null &&
                        !string.IsNullOrWhiteSpace(Author.Uri))
                    {
                        _userUrl = new Uri(Author.Uri);
                    }
                }

                return _userUrl;
            }
        }
    }
}